package com.syq.courierDelivery.common.utils;

import com.syq.courierDelivery.entity.po.Express;
import com.syq.courierDelivery.entity.po.ExpressDelivery;
import com.syq.courierDelivery.entity.vo.Coordinate;
import com.syq.courierDelivery.entity.vo.MqReceiveVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class PathPlanningUtils {


    public List<ExpressDelivery> pathPlan(MqReceiveVo mqReceiveVo) {
        //将地址转化成坐标 Map<String,Coordinate>
        List<Map<Long, Coordinate>> coordinateList = new ArrayList<>();
        List<Long> ids = new ArrayList<>();
        Map<Long, StringBuilder> duplicateIds = new HashMap<>();
        String[] coordinateCenter = mqReceiveVo.getCenterCoordinate().split(",");
        Coordinate coordinate = new Coordinate();
        coordinate.setX(coordinateCenter[0]);
        coordinate.setY(coordinateCenter[1]);
        convertCoordinates(coordinateList,mqReceiveVo.getDeliveryList(),ids,duplicateIds,coordinate);
        ACO aco = new ACO();
        //初始化数据： 距离、信息素等
        aco.init(coordinateList,ids,100);
        long t3 = System.currentTimeMillis();
        aco.run(200);
        long t2 = System.currentTimeMillis();
        System.out.println("计算耗时： "+  (t2-t3)/1000*1.00);
        //得到顺序，此顺序与传过去的ids顺序一致
        int[] bestTour = aco.ReportResult();
        List<Long> finalIds = new ArrayList<>();
        List<ExpressDelivery> finalExpressDeliveryList = new ArrayList<>();
        int indexOf0 = -1;
        // 结果的一个环，现需要得到0开头，且去掉原来的尾巴
        int[] newBestTour = new int[bestTour.length-1];
        //采用轮转数组的方法，先找到0的位置 i，然后轮转（size-i）次 即可得到0，。。。。开头的
        for (int i = 0; i < bestTour.length - 1; i++) {
            if(bestTour[i] == 0) {
                indexOf0 = i;
            }
            newBestTour[i] = bestTour[i];
        }
        if(indexOf0 != 0) {
            rotate(newBestTour,newBestTour.length-indexOf0);
        }

        //根据最终路径顺序，重组派件顺序
        for(int i = 0; i < newBestTour.length; i++) {
            int id = newBestTour[i];
            Long realId = ids.get(id);
            if(realId != -1) {
                finalIds.add(realId);
            }
            //若有同一地址的则加回来
            if(duplicateIds.containsKey(realId)) {
                StringBuilder stringBuilder = duplicateIds.get(realId);
                String[] strings = stringBuilder.toString().split(",");
                if(strings.length > 1) {
                    for(int j = 1; j < strings.length; j++) {
                        finalIds.add(Long.parseLong(strings[j]));
                    }
                }
            }
        }

        List<ExpressDelivery> deliveryList = mqReceiveVo.getDeliveryList();
        for(int i = 0; i < finalIds.size(); i++) {
            for(int j = 0; j < deliveryList.size(); j++) {
                if(deliveryList.get(j).getId() == finalIds.get(i)) {
                    finalExpressDeliveryList.add(deliveryList.get(j));
                    break;
                }
            }
        }

        return  finalExpressDeliveryList;
    }


    /**
     * @author Curry
     * @date 2022/3/30 13:27
     * 地址转换坐标
     * @return
     */
    public void convertCoordinates(List<Map<Long, Coordinate>> coordinateList, List<ExpressDelivery> expressDeliveryList, List<Long> ids,Map<Long,StringBuilder> duplicateIds, Coordinate coordinateCenter) {
        Map<Long, String> coordinates = new HashMap<>();
        Map<Long, Coordinate> coordinateCenterMap = new HashMap<>();
        String coordinateCenterString = new String(coordinateCenter.getX()+","+coordinateCenter.getY());
        coordinateCenterMap.put(-1l,coordinateCenter);
        coordinateList.add(coordinateCenterMap);
        ids.add(-1l);
        //去重 坐标一样的不进行计算
        if(expressDeliveryList != null && expressDeliveryList.size() > 0) {
            for(ExpressDelivery expressDelivery : expressDeliveryList) {
                Express express = expressDelivery.getExpress();
                // 若地址和快递驿站地址一致，则先加入重复的id集合
                if(coordinateCenterString.equals(express.getCoordinate())) {
                    StringBuilder stringBuilder = new StringBuilder("-1,"+expressDelivery.getId().toString());
                    if(duplicateIds.get(-1l) != null) {
                        StringBuilder stringBuilders = new StringBuilder(expressDelivery.getId().toString());
                        duplicateIds.get(-1l).append(",").append(stringBuilders);
                        continue;
                    }
                    duplicateIds.put(-1l,stringBuilder);
                    continue;
                }
                if(!coordinates.containsValue(express.getCoordinate())) {
                    ids.add(expressDelivery.getId());
                    coordinates.put(expressDelivery.getId(),express.getCoordinate());
                    StringBuilder stringBuilder = new StringBuilder(expressDelivery.getId().toString());
                    duplicateIds.put(expressDelivery.getId(),stringBuilder);
                } else {
                    Long id = getKey(coordinates,express.getCoordinate());
                    duplicateIds.get(id).append(",").append(expressDelivery.getId());
                }
            }
            for(ExpressDelivery expressDelivery : expressDeliveryList) {
                if(ids.contains(expressDelivery.getId())) {
                    Map<Long, Coordinate> coordinateMap = new HashMap<>();
                    Express express = expressDelivery.getExpress();
                    Coordinate coordinate = new Coordinate();
                    String[] xy = express.getCoordinate().split(",");
                    coordinate.setX(xy[0]);
                    coordinate.setY(xy[1]);
                    coordinateMap.put(expressDelivery.getId(),coordinate);
                    coordinateList.add(coordinateMap);
                }
            }
        }
    }

    public static Long getKey(Map<Long,String> map,String value){
        Long key = null;
        //Map,HashMap并没有实现Iteratable接口.不能用于增强for循环.
        for(Long getKey: map.keySet()){
            if(map.get(getKey).equals(value)){
                key = getKey;
            }
        }
        return key;
        //这个key肯定是最后一个满足该条件的key.
    }

    //旋转数组
    public void rotate(int[] nums, int k) {
        k %= nums.length;
        reverse(nums, 0, nums.length - 1);
        reverse(nums, 0, k - 1);
        reverse(nums, k, nums.length - 1);
    }

    public void reverse(int[] nums, int start, int end) {
        while (start < end) {
            int temp = nums[start];
            nums[start] = nums[end];
            nums[end] = temp;
            start += 1;
            end -= 1;
        }
    }

}
